package lib

import (
	"fmt"
	"fruit/actor/iactor"
	"fruit/common"
	"fruit/tools/proto/proto_out"
	"fruit/tools/proto/proto_out/base"
	"strconv"
	"sync"

	"google.golang.org/protobuf/proto"
)

var map_rou sync.Map
var proto_actor proto_out.IService_IProtoActor
var map_service sync.Map
var map_actor sync.Map

var pid string
var sli_event common.AllocSlice

type AsynActorFunc func(iact iactor.IActor, args ...interface{})

func Start(service proto_out.IService_IProtoActor) {
	sli_event.Init(50000)
	func_redis_start()
	pid = strconv.FormatInt(Index("default"), 10)

	proto_actor = service
	iact := proto_actor.(iactor.IActor)
	RegisterActor("default", iact, nil)
	// lib_rds.sadd(fmt.Sprintf("actor:%s", iactor.Type(iact)), iactor.Uid(iact))

	RunGoroutine(iact, "create_service", create_service)

	go redis_sub()
	// fmt.Println("fruit success... pid:", get_pid())
}

func Create(actor string, msg proto.Message) *base.CreateResp {
	parse := common.Adapt(actor)
	var to string
	_, succ := map_service.Load(parse.Service)
	if succ {
		to = get_pid()
	} else {
		to = lib_rds.srandmember(fmt.Sprintf("service:%s", parse.Service))
	}

	if to != "" {
		req_msg := &base.CreateReq{
			Type: actor,
			Data: func() []byte {
				msg, _ := proto.Marshal(msg)
				return msg
			}(),
		}
		resp := &base.CreateResp{}
		call(to, proto_out.ProtoFuncEnum_Create, req_msg, resp)
		return resp
	}
	return nil
}

func Destory(actor string) {
	// fmt.Println(":", actor)
	parse := common.Adapt(actor)
	// var to string
	// _, succ := map_service.Load(parse.Service)
	// if succ {
	// 	to = get_pid()
	// } else {
	// 	to = lib_rds.srandmember(fmt.Sprintf("service:%s", parse.Service))
	// }
	if parse.Service != "" {
		req_msg := &base.DestoryReq{
			Uid: actor,
		}
		Push(parse.Service, proto_out.ProtoFuncEnum_Destory, req_msg)
	}
}

func WakeUp(event_id uint64, from string, str []byte) {
	if event_id == 0 {
		return
	}
	ch := sli_event.Del(event_id)
	if ch == nil {
		fmt.Println("not found event_id", event_id)
		return
	}
	ch.(chan []byte) <- str

	parse := common.Adapt(from)
	is_my_service := parse.Service == get_pid()
	deal_to := common.IfGet(is_my_service, "同步", "异步").(string)
	fmt.Printf("%s %s 唤醒 event_id:%d\n", from, deal_to, event_id)
}

func Call(to string, func_name uint64, msg proto.Message, out proto.Message) {
	call(to, func_name, msg, out)
}

func Push(to string, func_name uint64, msg proto.Message) {
	iact := get_actor()
	if iact == nil {
		return
	}

	push(iact, to, func_name, 0, msg)
}

func Ping(to string) bool {
	// count := lib_rds.publish(to, nil)
	return lib_rds.publish(to, nil) > 0
}

func Stop() {
	lib_tcp.close()
	lib_rds.close()
}
